package geodata;

import java.io.Serializable;
import java.util.Observable;

import javax.swing.InputVerifier;
import javax.swing.JComponent;

import util.SerializableInputVerifier;

/**
 * An abstraction of the fields which represent variables that need to be set to
 * perform calculations.
 * 
 * @author Stephan Jossie
 * 
 */
@SuppressWarnings("serial")
public class Field<Number> extends Observable implements
		Serializable
{
	/**
	 * The display name of the field.
	 */
	public String displayName;

	/**
	 * A variable representation of the field. For example <code>v</code> for
	 * velocity.
	 */
	public String variable;

//	/**
//	 * The type of this field. For example <code>double</code>.
//	 */
//	public String type;

	/**
	 * An input verifier of the constraints.
	 */
	public SerializableInputVerifier constraints;

	/**
	 * The current value of this <code>Field</code>.
	 */
	public Number value;

	/**
	 * Constructs a field with a specified default value.
	 * 
	 * @param value
	 *            the initial value of the variable
	 * @param displayName
	 *            the display name of the variable
	 * @param variableName
	 *            the name of the variable
	 * @param variableType
	 *            the type of variable
	 * @param constraints
	 *            an InputVerifier for the field, may be <code>null</code>
	 */
	public Field(Number value, String displayName, String variableName,
			SerializableInputVerifier constraints)
	{
		this.value = value;
		this.variable = variableName;
//		this.type = variableType;
		this.constraints = constraints;
		this.displayName = displayName;

		if (this.constraints == null)
		{
			// create an "accept everything" input verifier
			this.constraints = new SerializableInputVerifier()
			{
				@Override
				public boolean verify(JComponent input)
				{
					return true;
				}
			};
		}
	}

//	/**
//	 * Constructs a field with a default value of 0.
//	 * 
//	 * @param displayName
//	 *            the display name of the variable
//	 * @param variableName
//	 *            the name of the variable
//	 * @param variableType
//	 *            the type of variable
//	 * @param constraints
//	 *            an InputVerifier for the field, may be <code>null</code>
//	 */
//	protected Field(String displayName, String variableName, String variableType,
//			InputVerifier constraints)
//	{
//		
//		this(null, displayName, variableName, variableType, constraints);
//		
//	}

	/**
	 * @return the value of this field's variable
	 */
	public Number getValue()
	{
		return value;
	}

	/**
	 * @param d
	 *            the new value of this field
	 */
	public void setValue(double d)
	{
		this.value = (Number) new Double(d);
		notifyObservers();
	}

	/**
	 * @return the display name of this variable
	 */
	public String getDisplayName()
	{
		return displayName;
	}

	/**
	 * @return the variable name for this field
	 */
	public String getVariable()
	{
		return variable;
	}

//	/**
//	 * @return the type of variable in this field
//	 */
//	public String getType()
//	{
//		return type;
//	}

	/**
	 * @return an <code>InputVerifier</code> to verify the particular field.
	 *         Will always return a verifier.
	 */
	public InputVerifier getConstraints()
	{
		return constraints;
	}

	@Override
	public int hashCode()
	{
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((displayName == null) ? 0 : displayName.hashCode());
		result = prime * result + ((value == null) ? 0 : value.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj)
	{
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Field other = (Field) obj;
		if (displayName == null)
		{
			if (other.displayName != null)
				return false;
		}
		else if (!displayName.equals(other.displayName))
			return false;
		if (value == null)
		{
			if (other.value != null)
				return false;
		}
		else if (!value.equals(other.value))
			return false;
		return true;
	}
}
